package com.blustreaksw.cyclecoach.userManagment;

import java.util.ArrayList;

import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.blustreaksw.cyclecoach.R;
import com.blustreaksw.cyclecoach.UserProfileActivity;
import com.blustreaksw.cyclecoach.MainActivity;
import com.blustreaksw.cyclecoach.btle.BtleDeviceType;
import com.blustreaksw.cyclecoach.btle.BtleDiscoveryManager;
import com.blustreaksw.cyclecoach.data.UserProfile;
import com.blustreaksw.cyclecoach.util.ConfirmationDialogFragment;

/***********************************************************************
 * Display creation and UI logic for BTLE Device search fragment.
 * 
 * @author Tomas Rivera
 *
 ***********************************************************************/
public class Fragment_BtleDeviceSearch extends ListFragment {
	
	private static final String TAG = "Fragment_BtleDeviceSearch";
	
	/***********************************************************************
     * Bundle key for transferring BtleDeviceType to search for.
     ***********************************************************************/
	public static final String EXTRA_BTLE_DEVICE_TYPE =  
			Fragment_BtleDeviceSearch.class.getPackage().getName() + ".extra_btle_device_type";
	
	private boolean mBtleScanRunning;
	private BtleDiscoveryManager mBtleDiscoveryManager;
	private BtleDeviceType mDeviceType;
	private final int SCANNING_TIMEOUT = 10000;
	private Handler mHandler;
	private ArrayList<DeviceContainer> mDeviceContainerList;
	private TextView mEmptyView;
	
	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.Fragment#onCreate(android.os.Bundle)
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setHasOptionsMenu(true);
		setRetainInstance(true);
		mHandler = new Handler();
		mDeviceContainerList = new ArrayList<DeviceContainer>();
		DeviceAdapter deviceAdapter = new DeviceAdapter(mDeviceContainerList);
		setListAdapter(deviceAdapter);
		
		
		Bundle bundle = this.getArguments();
		mDeviceType = BtleDeviceType.fromInt(bundle.getInt(EXTRA_BTLE_DEVICE_TYPE));
		mBtleDiscoveryManager = new BtleDiscoveryManager(mDeviceType, getActivity().getApplicationContext(), mDiscoveryCallback);
		
		if(mBtleDiscoveryManager == null) {
			
		} else if(mBtleDiscoveryManager.initBt() == false) {
			
		} else if(mBtleDiscoveryManager.isBleAvailable() == false) {
			
		} else if(mBtleDiscoveryManager.isBtEnabled() == false) {
			mBtleScanRunning = false;
			getActivity().invalidateOptionsMenu();
			new ConfirmationDialogFragment().configureDialog(new DialogInterface.OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int arg1) {
					// Handle Ok
					Intent intentBluetooth = new Intent();
				    intentBluetooth.setAction(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS);
				    startActivity(intentBluetooth);
				}
			}, new DialogInterface.OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int arg1) {
					// Handle Cancel
					getActivity().getSupportFragmentManager().popBackStackImmediate();
				}
			}, "Bluetooth Unavailable", "Bluetooth radio must be turned on to proceed. Click Ok to go to settings, " +
				"or Cancel to skip searching for Bluetooth devices.", getActivity())
			.onCreateDialog(null).show();
			
		} else {
			startBtleScan();
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.ListFragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
	 */
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
		View v = inflater.inflate(R.layout.list_empty, parent, false);
		mEmptyView = (TextView)v.findViewById(R.id.emptyView);
		mEmptyView.setText("No devices found");
		
		
		getActivity().getActionBar().setDisplayHomeAsUpEnabled(false);
        getActivity().getActionBar().setHomeButtonEnabled(false);
        getActivity().getActionBar().setSubtitle(null);
		
		return v;
	}
	
	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.Fragment#onPrepareOptionsMenu(android.view.Menu)
	 */
	@Override
	public void onPrepareOptionsMenu(Menu menu) {
		
		if(mBtleScanRunning) {
			menu.findItem(R.id.scanning_indicator).setActionView(R.layout.progress_indicator).setVisible(true);
			menu.findItem(R.id.action_createUserWizard_restartDeviceScan).setVisible(false);
		} else {
			menu.findItem(R.id.scanning_indicator).setActionView(R.layout.progress_indicator).setVisible(false);
			menu.findItem(R.id.action_createUserWizard_restartDeviceScan).setVisible(true);
		}
		
		menu.findItem(R.id.action_createUserWizard_cancelButton).setVisible(true);
		
		if(((UserProfileActivity)getActivity()).isWizardActivity()) {
		// Hidden options
			menu.findItem(R.id.action_createUserWizard_newUser).setVisible(false);
			menu.findItem(R.id.action_createUserWizard_prevButton).setVisible(false);
			menu.findItem(R.id.action_createUserWizard_nextButton).setVisible(false);
			menu.findItem(R.id.action_createUserWizard_saveButton).setVisible(false);
		} else {
			menu.findItem(R.id.action_history).setVisible(false);
			menu.findItem(R.id.action_changeUser).setVisible(false);
			menu.findItem(R.id.action_musicPlayerExternalLink).setVisible(false);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.Fragment#onOptionsItemSelected(android.view.MenuItem)
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
    	switch(item.getItemId()) {
    		case R.id.action_createUserWizard_restartDeviceScan:
    			startBtleScan();
    			return true;

    		case R.id.action_createUserWizard_cancelButton:
    			stopBtleScan();
    			getActivity().getSupportFragmentManager().popBackStackImmediate();
    			return true;
    		
    		case R.id.action_createUserWizard_newUser:
    		case R.id.action_createUserWizard_nextButton:
    		case R.id.action_createUserWizard_prevButton:
    		case R.id.action_createUserWizard_saveButton:   		
    		default:
    			return super.onOptionsItemSelected(item); 
    	}
	}
	
	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.ListFragment#onListItemClick(android.widget.ListView, android.view.View, int, long)
	 */
	@Override
	public void onListItemClick(ListView l, View v, int position, long id) {
		
		DeviceContainer deviceContainer = ((DeviceAdapter)getListAdapter()).getItem(position);
        final BluetoothDevice device = deviceContainer.getDevice();
        if (device == null) return;
        
        if (mBtleScanRunning) {
            stopBtleScan();
        }
        
        final String message = new String(
        		String.format("Selected:\n%s\n%s\nPair with this device?", device.getName(), device.getAddress()));

        new ConfirmationDialogFragment().configureDialog(new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int arg1) {
				// User clicked OK so add the device info to the UserProfile.
				if(mDeviceType.equals(BtleDeviceType.HEART_RATE_MONITOR)) {
					getUserProfileFromActivity().setHeartRateMonitorName(device.getName());
					getUserProfileFromActivity().setHeartRateMonitorAddress(device.getAddress());
					
				} else if(mDeviceType.equals(BtleDeviceType.CYCLING_SPEED_CADENCE_SENSOR)) {
					getUserProfileFromActivity().setCyclingSpeedCadenceSensorName(device.getName());
					getUserProfileFromActivity().setCyclingSpeedCadenceSensorAddress(device.getAddress());
					
				} else if(mDeviceType.equals(BtleDeviceType.CYCLING_POWER_METER)) {
					getUserProfileFromActivity().setCyclingPowerMeterName(device.getName());
					getUserProfileFromActivity().setCyclingPowerMeterAddress(device.getAddress());
					
				}
				

				if(((UserProfileActivity)getActivity()).isWizardActivity() == false) {
					getUserProfileFromActivity().updateUserFromCurrentProfileValues(getActivity());
					((MainActivity)getActivity()).newDeviceAdded(mDeviceType, device.getAddress());
				}
				
				// Return to the calling fragment.
				getActivity().getSupportFragmentManager().popBackStackImmediate();
			}
		}, new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int arg1) {
				// User clicked cancel so just return to the device list
			}
		}, "Confirm Selection", message, getActivity())
		.onCreateDialog(null).show();
    }
	
	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.Fragment#onPause()
	 */
	@Override
	public void onPause() {
		super.onPause();
		stopBtleScan();
	}
	
	/*
	 * (non-Javadoc)
	 * @see android.support.v4.app.Fragment#onResume()
	 */
	@Override
	public void onResume() {
		getActivity().setTitle("Bluetooth LE Discovery");
		((DeviceAdapter)getListAdapter()).notifyDataSetChanged();
		super.onResume();
	}
	
	
	/********************************************************************************
	 * Starts BtleDiscoveryManager (BluetoothAdapter) LE scan. Automatically
	 * times out after a specified period and aborts the scan.
	 ********************************************************************************/
	public void startBtleScan() {
		mBtleScanRunning = true;
		getActivity().invalidateOptionsMenu();
		mBtleDiscoveryManager.searchForDevices();
		mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
            	if(mBtleScanRunning == false) return;
            	Log.d(TAG, "(addScanningTimeout) BtleDevice search has timed out.");
            	stopBtleScan();
            	getActivity().invalidateOptionsMenu();
            }
        }, SCANNING_TIMEOUT);
	}
	
	/********************************************************************************
	 * Aborts BtleDiscoveryManager (BluetoothAdapter) LE scan.
	 ********************************************************************************/
	public void stopBtleScan() {
		mBtleScanRunning = false;
		mBtleDiscoveryManager.stopSearchingForDevices();
	}
	
	/*
	 * Callback definition required by BtleDiscoveryManager.
	 */
	private BtleDiscoveryManager.BtleDiscoveryManagerCallback mDiscoveryCallback = new BtleDiscoveryManager.BtleDiscoveryManagerCallback() {
		
		@Override
		public void onDeviceFound(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
			// adding to the UI have to happen in UI thread
			getActivity().runOnUiThread(new Runnable() {
				@Override
				public void run() {
					mDeviceContainerList.add(new DeviceContainer(device, rssi, scanRecord));
					((DeviceAdapter)getListAdapter()).notifyDataSetChanged();
				}
			});
		}
	};
	
	/*
	 * Returns UserProfile object from hosting activity.
	 */
	private UserProfile getUserProfileFromActivity() { return ((UserProfileActivity)getActivity()).getUserProfile(); }
	
	/*
	 * Convenience class that contains attributes for a Bluetooth device
	 * found during the LE scan. 
	 */
	private class DeviceContainer {
		private BluetoothDevice device;
		private int rssi;
		private byte[] scanRecord;
		
		DeviceContainer (BluetoothDevice d, int r, byte[] s) {
			device = d;
			rssi = r;
			scanRecord = s;
		}
		
		public BluetoothDevice getDevice() { return device; }
		public int getRssi() { return rssi; }
		public byte[] getScanRecord() { return scanRecord; }
	}
	
	/*
	 * Container for the clickable list of Bluetooth LE devices that 
	 * can be presented to the user to choose from.
	 */
	private class DeviceAdapter extends ArrayAdapter<DeviceContainer> {
		
		public DeviceAdapter(ArrayList<DeviceContainer> devices) {
			super(getActivity(), 0, devices);
		}
		
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			if(convertView == null) {
				convertView = getActivity().getLayoutInflater().inflate(R.layout.fragment_btle_scanning_item, null);
			}
			
			DeviceContainer d = getItem(position);
			
			TextView deviceNameTextView = (TextView)convertView.findViewById(R.id.deviceName);
			deviceNameTextView.setText(d.getDevice().getName());
			
			TextView deviceAddressTextView = (TextView)convertView.findViewById(R.id.deviceAddress);
			deviceAddressTextView.setText(d.getDevice().getAddress());
			
			TextView deviceRssiTextView = (TextView)convertView.findViewById(R.id.deviceRssi);
			deviceRssiTextView.setText(Integer.toString(d.getRssi()));
			
			
			return convertView;
		}
	}
	
	
}
